/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.meego.common.crypto;


import com.meego.common.crypto.KeyStore.KeyStoreType;
import com.meego.common.log.GA;
import com.meego.common.util.ByteUtils;
import com.meego.common.util.HexUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateCrtKeySpec;
import java.util.Enumeration;
import java.util.Properties;

/**
 *
 * @author TueHM
 */
public class MeegoKeyStore {

    private Properties list;

    public MeegoKeyStore() {
        this.list = new Properties();
    }

    public Enumeration addresses() {
        return this.list.keys();
    }

    public void add(String address, byte[] key) {
        if (key != null) {
            char[] encoded = new char[key.length * 2];

            for (int i = 0; i < key.length; i++) {
                int bit = key[i];
                if (bit < 0) {
                    bit += 256;
                }

                encoded[(i * 2)] = HexUtil.encodeHex(bit / 16);
                encoded[(i * 2 + 1)] = HexUtil.encodeHex(bit & 0xF);
            }

            this.list.setProperty(address, new String(encoded));
        } else {
            this.list.setProperty(address, "");
        }
    }

    public void addString(String name, String value) {
        if (value != null) {
            this.list.setProperty(name, value);
        } else {
            this.list.setProperty(name, "");
        }
    }

    public byte[] get(String address) {
        String key = this.list.getProperty(address);
        if (key == null) {
            return null;
        }

        byte[] bits = new byte[key.length() / 2];
        for (int i = 0; i < bits.length; i++) {
            bits[i] = (byte) (HexUtil.decodeHex(key.charAt(i * 2)) * 16 + HexUtil.decodeHex(key.charAt(i * 2 + 1)));
        }

        return bits;
    }

    public String getString(String name) {
        return this.list.getProperty(name);
    }

    public void remove(String address) {
        this.list.remove(address);
    }

    public boolean exists(String address) {
        return this.list.getProperty(address, null) != null;
    }

    public void load(InputStream is, char[] passphrase) throws IOException {
        this.list = new Properties();
        InputStream sis = new SignedInputStream(is, passphrase);
        this.list.load(sis);
        sis.close();
    }

    public void save(OutputStream os, char[] passphrase) throws IOException {
        OutputStream sos = new SignedOutputStream(os, passphrase);
        this.list.store(sos, "OPS SecretKey Store");
        sos.close();
    }

    public void createNewKey(KeyStoreType keyStoreType, int index, String filePath, int keysize) throws Exception {
        String prefix = new StringBuilder().append(keyStoreType.toString().toLowerCase()).append(".").append(index).toString();
        MeegoKeyStore keyStore = new MeegoKeyStore();
        try {
            KeyFactory kf = KeyFactory.getInstance("RSA");
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            if (keysize < 128) {
                throw new IllegalArgumentException("Invalid key size[Key size must be greater than 128]");
            }
            if (keysize % 2 != 0) {
                throw new IllegalArgumentException("Invalid key size[Key size must be divisible by 2]");
            }
            kpg.initialize(1024);
            KeyPair kp = kpg.generateKeyPair();
            RSAPrivateCrtKeySpec ks = kf.getKeySpec(kp.getPrivate(), RSAPrivateCrtKeySpec.class);

            keyStore.add(prefix + ".modulus", ks.getModulus().toByteArray());
            keyStore.add(prefix + ".pub", ks.getPublicExponent().toByteArray());
            keyStore.add(prefix + ".private", ks.getPrivateExponent().toByteArray());
            keyStore.add(prefix + ".p", ks.getPrimeP().toByteArray());
            keyStore.add(prefix + ".q", ks.getPrimeQ().toByteArray());
            keyStore.add(prefix + ".dP", ks.getPrimeExponentP().toByteArray());
            keyStore.add(prefix + ".dQ", ks.getPrimeExponentQ().toByteArray());
            keyStore.add(prefix + ".qInv", ks.getCrtCoefficient().toByteArray());

            SecureRandom random = new SecureRandom();
            keyStore.add(prefix + ".df", new BigInteger(50, random).toByteArray());
            keyStore.add(prefix + ".iv", new BigInteger(80, random).toByteArray());

            File file = new File(filePath);
            if(!file.exists()){
                file.mkdirs();
            }
            FileOutputStream os = new FileOutputStream(filePath);
            keyStore.save(os, ByteUtils.bytesToString(KeyStore.editorSeed).toCharArray());
        } catch (Exception e) {
            GA.crypto.error("Create new key fail", e);
            throw e;
        }
    }
}
